# 创建和使用类
# 使用类几乎可以模拟任何东西。下面来编写一个表示小狗的简单
# 类Dog ，它表示的不是特定的小狗，而是任何小狗。对于大多数宠
# 物狗，我们都知道些什么呢？它们都有名字和年龄。我们还知道，
# 大多数小狗还会蹲下和打滚。由于大多数小狗都具备上述两项信息
# （名字和年龄）和两种行为（蹲下和打滚），我们的Dog 类将包含
# 它们。这个类让Python知道如何创建表示小狗的对象。编写这个类
# 后，我们将使用它来创建表示特定小狗的实例。

# 创建Dog类
# 根据Dog 类创建的每个实例都将存储名字和年龄，我们赋予了每条小狗蹲下（sit() ）和打滚（roll_over() ）的能力：
# dog.py
class Dog:									# 定义了一个名为Dog 的类。根据约定，在Python中，首字母大写的名称指的是类。这个类定义中没有圆括号，因为要从空白创建这个类
	"""一次模拟小狗的简单尝试"""

	def __init__(self, name, age):
		"""初始化属性name和age"""
		self.name = name					# 以self 为前缀的变量可供类中的所有方法使用，可以通过类的任何实例来访问。self.name =name 获取与形参name 相关联的值，
		self.age = age						# 并将其赋给变量name ，然后该变量被关联到当前创建的实例。self.age = age 的作用与此类似。像这样可通过实例访问的变量称为属性 。

	# 方法__init__()
	# 类中的函数称为方法 。在前面学到的有关函数的一切都适用于方法，就目前而言，唯一重要的差别是调用方法的方式
	# 方法__init__() 是一个特殊方法，每当你根据Dog 类创建新实例时，Python都会自动运行它。
	# 在这个方法的名称中，开头和末尾各有两个下划线，这是一种约定，旨在避免Python默认方法与普通方法发生名称冲突。
	# 务必确保__init__() 的两边都有两个下划线，否则当你使用类来创建实例时，将不会自动调用这个方法，进而引发难以发现的错误。

	# 包含三个形参：self 、name 和age 。在这个方法的定义中，形参self 必不可少，而且必须位于其他形参的前面。
	# 为何必须在方法定义中包含形参self 呢？因为Python调用这个方法来创建Dog 实例时，将自动传入实参self 。
	# 每个与实例相关联的方法调用都自动传递实参self ，它是一个指向实例本身的引用，让实例能够访问类中的属性和方法。
	# 创建Dog 实例时，Python将调用Dog 类的方法__init__() 。我们将通过实参向Dog() 传递名字和年龄，self 会自动传递，
	# 因此不需要传递它。每当根据Dog 类创建实例时，都只需给最后两个形参（name和age ）提供值。

	def sit(self):
		"""模拟小狗收到命令时蹲下"""
		print(f"{self.name} is now sitting.")

	def roll_over(self):
		"""模拟小狗收到命令时打滚"""
		print(f"{self.name} rolled over!")

	# Dog 类还定义了另外两个方法：sit() 和roll_over()
	# 这些方法执行时不需要额外的信息，因此它们只有一个形参self。我们随后将创建的实例能够访问这些方法，换句话说，它们都会
	# 蹲下和打滚。当前，sit() 和roll_over() 所做的有限，只是打印一条消息，指出小狗正在蹲下或打滚。但可以扩展这些方法以模
	# 拟实际情况：如果这个类包含在一个计算机游戏中，这些方法将包含创建小狗蹲下和打滚动画效果的代码；如果这个类是用于控制机
	# 器狗的，这些方法将让机器狗做出蹲下和打滚的动作。


# 根据类创建实例
# 可将类视为有关如何创建实例的说明。Dog 类是一系列说明，让Python知道如何创建表示特定小狗的实例。
# 下面来创建一个表示特定小狗的实例：
class Dog:
	"""一次模拟小狗的简单尝试"""

	def __init__(self, name, age):
		"""初始化属性name和age"""
		self.name = name
		self.age = age

	def sit(self):
		"""模拟小狗收到命令时蹲下"""
		print(f"{self.name} is now sitting.")

	def roll_over(self):
		"""模拟小狗收到命令时打滚"""
		print(f"{self.name} rolled over!")

my_dog = Dog('Willie', 6)		# 使用实参'Willie' 和6 调用Dog 类的方法__init__() 。
# 方法__init__() 创建一个表示特定小狗的实例，并使用提供的值来设置属性name 和age 。
# 接下来，Python返回一个表示这条小狗的实例，而我们将这个实例赋给了变量my_dog 。
# 在这里，命名约定很有用：通常可认为首字母大写的名称（如Dog ）指的是类，而小写的名称（如my_dog ）指的是根据类创建的实例。
print(f"My dog's name is {my_dog.name}.")	# my_dog.name 访问my_dog 的属性name 的值
print(f"My dog is {my_dog.age} years old.")

# 调用方法
# 根据Dog 类创建实例后，就能使用句点表示法来调用Dog 类中定义的任何方法了。
# 下面来让小狗蹲下和打滚：
my_dog.sit()			# 运行代码my_dog.sit() 时，Python在类Dog 中查找方法sit() 并运行其代码。
my_dog.roll_over()		# Python以同样的方式解读代码my_dog.roll_over() 。

# 如果给属性和方法指定了合适的描述性名称，如name 、age 、sit() 和roll_over() ，
# 即便是从未见过的代码块，我们也能够轻松地推断出它是做什么的。


# 创建多个实例
# 可按需求根据类创建任意数量的实例。下面再创建一个名为your_dog 的小狗实例：
my_dog = Dog('Willie', 6)
your_dog = Dog('Lucy', 3)

print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")
my_dog.sit()

print(f"\nYour dog's name is {your_dog.name}.")
print(f"Your dog is {your_dog.age} years old.")
your_dog.sit()

# 在本例中创建了两条小狗，分别名为Willie和Lucy。每条小狗都是一个独立的实例，有自己的一组属性，能够执行相同的操作
# 即使给第二条小狗指定同样的名字和年龄，Python依然会根据Dog 类创建另一个实例。
# 可按需求根据一个类创建任意数量的实例，条件是将每个实例都存储在不同的变量中，或者占用列表或字典的不同位置。
